package org.jsola.hr.service.impl;

import com.alibaba.fastjson.JSON;
import org.jsola.common.DateKit;
import org.jsola.core.Page;
import org.jsola.exception.JsolaException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.common.HrLogKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.constant.ProgTypeEnum;
import org.jsola.hr.dao.IAttendanceDedDAO;
import org.jsola.hr.dao.IAttendanceDedItemDAO;
import org.jsola.hr.dao.IAttendanceDedParamDAO;
import org.jsola.hr.dao.IAttendanceDedProgDAO;
import org.jsola.hr.dto.*;
import org.jsola.hr.entity.AttendanceDedDO;
import org.jsola.hr.entity.AttendanceDedItemDO;
import org.jsola.hr.entity.AttendanceDedParamDO;
import org.jsola.hr.entity.AttendanceDedProgDO;
import org.jsola.hr.exception.HrException;
import org.jsola.hr.query.AttendanceDedProgQuery;
import org.jsola.hr.service.IApplyToProgService;
import org.jsola.hr.service.IAttendanceDedProgService;
import org.jsola.hr.vo.ApplyToProgVO;
import org.jsola.hr.vo.AttendanceDedProgListVO;
import org.jsola.hr.vo.AttendanceDedProgVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhr
 */
@Service("hrAttendanceDedProgServiceImpl")
public class AttendanceDedProgServiceImpl implements IAttendanceDedProgService {

    @Autowired
    private IAttendanceDedProgDAO attendanceDedProgDAO;

    @Autowired
    private IAttendanceDedDAO attendanceDedDAO;

    @Autowired
    private IAttendanceDedItemDAO attendanceDedItemDAO;

    @Autowired
    private IAttendanceDedParamDAO attendanceDedParamDAO;

    @Autowired
    private IApplyToProgService applyToProgService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public AttendanceDedProgVO save(AttendanceDedProgAddDTO attendanceDedProgAddDTO, TokenUser tokenUser) {
        Example example = new Example(AttendanceDedProgDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("companyId", attendanceDedProgAddDTO.getCompanyId())
                .andEqualTo("name", attendanceDedProgAddDTO.getName());
        Integer attendanceDedProgCount = attendanceDedProgDAO.selectCountByExample(example);
        if (attendanceDedProgCount > 0) {
            throw new HrException("方案名称已存在");
        }

        // 转DO
        AttendanceDedProgDO attendanceDedProgDO = attendanceDedProgAddDTO.to(AttendanceDedProgDO.class);
        HrLogKit.logForSave("新增员工考勤扣款方案", "saveAttendanceDedProg", attendanceDedProgDO.getId(), tokenUser);
        // 保存
        attendanceDedProgDO = save(attendanceDedProgDO, tokenUser.getSiteId(), tokenUser.getUserId());

        Date now = DateKit.getToday();
        if (!CollectionUtils.isEmpty(attendanceDedProgAddDTO.getAttendanceDedDOList())) {
            AttendanceDedProgDO finalAttendanceDedProgDO = attendanceDedProgDO;
            attendanceDedProgAddDTO.getAttendanceDedDOList().stream().map(attendanceDedDO -> {
                attendanceDedDO.setProgrammeId(finalAttendanceDedProgDO.getId());
                attendanceDedDO.setId(null);
                attendanceDedDO.setSiteId(tokenUser.getSiteId());
                attendanceDedDO.setValid(true);
                attendanceDedDO.setCreateUserId(tokenUser.getUserId());
                attendanceDedDO.setGmtCreate(now);
                attendanceDedDO.setModifiedUserId(tokenUser.getUserId());
                attendanceDedDO.setGmtModified(now);
                return attendanceDedDO;
            }).collect(Collectors.toList());
            List<AttendanceDedDO> attendanceDedDOList = attendanceDedProgAddDTO.getAttendanceDedDOList();
            //保存考勤扣款设置列表
            attendanceDedDAO.insertListAndSetId(attendanceDedDOList);

            List<AttendanceDedItemDO> attendanceDedItemDOListAll = new ArrayList<>();
            List<AttendanceDedParamDO> attendanceDedParamDOListAll = new ArrayList<>();
            attendanceDedDOList.stream().map(attendanceDedDO -> {
                if (!CollectionUtils.isEmpty(attendanceDedDO.getAttendanceDedItemDOList())) {
                    attendanceDedDO.getAttendanceDedItemDOList().stream().map(attendanceDedItemDO -> {
                        attendanceDedItemDO.setParentId(attendanceDedDO.getId());
                        attendanceDedItemDO.setId(null);
                        attendanceDedItemDO.setSiteId(tokenUser.getSiteId());
                        attendanceDedItemDO.setValid(true);
                        attendanceDedItemDO.setCreateUserId(tokenUser.getUserId());
                        attendanceDedItemDO.setGmtCreate(now);
                        attendanceDedItemDO.setModifiedUserId(tokenUser.getUserId());
                        attendanceDedItemDO.setGmtModified(now);
                        return attendanceDedDO;
                    }).collect(Collectors.toList());
                }
                attendanceDedItemDOListAll.addAll(attendanceDedDO.getAttendanceDedItemDOList());
                return attendanceDedItemDOListAll;
            }).collect(Collectors.toList());

            //保存考勤扣款设置子项列表
            if (!CollectionUtils.isEmpty(attendanceDedItemDOListAll)) {
                attendanceDedItemDAO.insertListAndSetId(attendanceDedItemDOListAll);

                attendanceDedItemDOListAll.stream().map(attendanceDedItemDO -> {
                    if (!CollectionUtils.isEmpty(attendanceDedItemDO.getAttendanceDedParamDOList())) {
                        attendanceDedItemDO.getAttendanceDedParamDOList().stream().map(attendanceDedParamDO -> {
                            attendanceDedParamDO.setItemId(attendanceDedItemDO.getId());
                            attendanceDedParamDO.setId(null);
                            attendanceDedParamDO.setSiteId(tokenUser.getSiteId());
                            attendanceDedParamDO.setValid(true);
                            attendanceDedParamDO.setCreateUserId(tokenUser.getUserId());
                            attendanceDedParamDO.setGmtCreate(now);
                            attendanceDedParamDO.setModifiedUserId(tokenUser.getUserId());
                            attendanceDedParamDO.setGmtModified(now);
                            return attendanceDedParamDO;
                        }).collect(Collectors.toList());
                    }
                    attendanceDedParamDOListAll.addAll(attendanceDedItemDO.getAttendanceDedParamDOList());
                    return attendanceDedParamDOListAll;
                }).collect(Collectors.toList());

                //保存考勤扣款设置参数项
                if (!CollectionUtils.isEmpty(attendanceDedParamDOListAll)) {
                    attendanceDedParamDAO.insertListAndSetId(attendanceDedParamDOListAll);
                }
            }


        }
        //保存方案适用设置
        ApplyToProgAddDTO applyToProgAddDTO = attendanceDedProgAddDTO.getApplyToProgAddDTO();
        applyToProgAddDTO.setBusProgType(ProgTypeEnum.ATTENDANCE_DED.getValue());
        applyToProgAddDTO.setBusProgId(attendanceDedProgDO.getId());
        applyToProgAddDTO.setMutex(true);
        Object obj = applyToProgService.add(applyToProgAddDTO, tokenUser);
        if (obj.getClass() != ApplyToProgVO.class) {
            throw new JsolaException(JSON.toJSONString(obj));
        }

        return attendanceDedProgDO.to(AttendanceDedProgVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(AttendanceDedProgUpdateDTO attendanceDedProgUpdateDTO, TokenUser tokenUser) {
        Example example = new Example(AttendanceDedProgDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("companyId", attendanceDedProgUpdateDTO.getCompanyId())
                .andEqualTo("name", attendanceDedProgUpdateDTO.getName())
                .andNotEqualTo("id", attendanceDedProgUpdateDTO.getId());
        int attendanceDedProgCount = attendanceDedProgDAO.selectCountByExample(example);
        if (attendanceDedProgCount > 0) {
            throw new HrException("方案名称已存在");
        }

        //转DO
        AttendanceDedProgDO attendanceDedProgDO = attendanceDedProgUpdateDTO.to(AttendanceDedProgDO.class);

        //删除考勤扣款设置列表
        AttendanceDedDO attendanceDedDO = new AttendanceDedDO();
        attendanceDedDO.setSiteId(tokenUser.getSiteId());
        attendanceDedDO.setProgrammeId(attendanceDedProgUpdateDTO.getId());
        List<AttendanceDedDO> attendanceDedDOListDel = attendanceDedDAO.select(attendanceDedDO);
        List<String> attendanceDedIdList = new ArrayList<String>() {{
            add(null);
        }};
        List<String> attendanceDedItemIdList = new ArrayList<String>() {{
            add(null);
        }};
        attendanceDedDOListDel.stream().map(attendanceDedDOTmp -> {
            attendanceDedIdList.add(attendanceDedDOTmp.getId());
            return attendanceDedIdList;
        }).collect(Collectors.toList());
        attendanceDedDAO.delete(attendanceDedDO);

        //删除考勤扣款设置子项列表
        Example exampleDedItem = new Example(AttendanceDedItemDO.class);
        exampleDedItem.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andIn("parentId", attendanceDedIdList);
        List<AttendanceDedItemDO> attendanceDedItemDOList = attendanceDedItemDAO.selectByExample(exampleDedItem);
        attendanceDedItemDOList.stream().map(attendanceDedItemDOTmp -> {
            attendanceDedItemIdList.add(attendanceDedItemDOTmp.getId());
            return attendanceDedItemIdList;
        }).collect(Collectors.toList());
        attendanceDedItemDAO.deleteByExample(exampleDedItem);

        //删除考勤扣款设置参数列表
        Example exampleDedParam = new Example(AttendanceDedParamDO.class);
        exampleDedParam.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andIn("itemId", attendanceDedItemIdList);
        attendanceDedParamDAO.deleteByExample(exampleDedParam);

        Date now = DateKit.getToday();
        if (!CollectionUtils.isEmpty(attendanceDedProgUpdateDTO.getAttendanceDedDOList())) {
            AttendanceDedProgDO finalAttendanceDedProgDO = attendanceDedProgDO;
            attendanceDedProgUpdateDTO.getAttendanceDedDOList().stream().map(attendanceDedDOTmp -> {
                attendanceDedDOTmp.setProgrammeId(finalAttendanceDedProgDO.getId());
                attendanceDedDOTmp.setId(null);
                attendanceDedDOTmp.setSiteId(tokenUser.getSiteId());
                attendanceDedDOTmp.setValid(true);
                attendanceDedDOTmp.setCreateUserId(tokenUser.getUserId());
                attendanceDedDOTmp.setGmtCreate(now);
                attendanceDedDOTmp.setModifiedUserId(tokenUser.getUserId());
                attendanceDedDOTmp.setGmtModified(now);
                return attendanceDedDOTmp;
            }).collect(Collectors.toList());
            List<AttendanceDedDO> attendanceDedDOList = attendanceDedProgUpdateDTO.getAttendanceDedDOList();
            //保存考勤扣款设置列表
            if (!CollectionUtils.isEmpty(attendanceDedDOList)) {
                attendanceDedDAO.insertListAndSetId(attendanceDedDOList);
            }
            List<AttendanceDedItemDO> attendanceDedItemDOListAll = new ArrayList<>();
            List<AttendanceDedParamDO> attendanceDedParamDOListAll = new ArrayList<>();
            attendanceDedDOList.stream().map(attendanceDedDOTmp -> {
                if (!CollectionUtils.isEmpty(attendanceDedDOTmp.getAttendanceDedItemDOList())) {
                    attendanceDedDOTmp.getAttendanceDedItemDOList().stream().map(attendanceDedItemDO -> {
                        attendanceDedItemDO.setParentId(attendanceDedDOTmp.getId());
                        attendanceDedItemDO.setId(null);
                        attendanceDedItemDO.setSiteId(tokenUser.getSiteId());
                        attendanceDedItemDO.setValid(true);
                        attendanceDedItemDO.setCreateUserId(tokenUser.getUserId());
                        attendanceDedItemDO.setGmtCreate(now);
                        attendanceDedItemDO.setModifiedUserId(tokenUser.getUserId());
                        attendanceDedItemDO.setGmtModified(now);
                        return attendanceDedItemDO;
                    }).collect(Collectors.toList());
                }

                attendanceDedItemDOListAll.addAll(attendanceDedDOTmp.getAttendanceDedItemDOList());
                return attendanceDedItemDOListAll;
            }).collect(Collectors.toList());

            //保存考勤扣款设置子项列表
            if (!CollectionUtils.isEmpty(attendanceDedItemDOListAll)) {
                attendanceDedItemDAO.insertListAndSetId(attendanceDedItemDOListAll);

                attendanceDedItemDOListAll.stream().map(attendanceDedItemDO -> {
                    attendanceDedItemDO.getAttendanceDedParamDOList().stream().map(attendanceDedParamDO -> {
                        attendanceDedParamDO.setItemId(attendanceDedItemDO.getId());
                        attendanceDedParamDO.setId(null);
                        attendanceDedParamDO.setSiteId(tokenUser.getSiteId());
                        attendanceDedParamDO.setValid(true);
                        attendanceDedParamDO.setCreateUserId(tokenUser.getUserId());
                        attendanceDedParamDO.setGmtCreate(now);
                        attendanceDedParamDO.setModifiedUserId(tokenUser.getUserId());
                        attendanceDedParamDO.setGmtModified(now);
                        return attendanceDedParamDO;
                    }).collect(Collectors.toList());
                    attendanceDedParamDOListAll.addAll(attendanceDedItemDO.getAttendanceDedParamDOList());
                    return attendanceDedParamDOListAll;
                }).collect(Collectors.toList());

                //保存考勤扣款设置参数项
                if (!CollectionUtils.isEmpty(attendanceDedParamDOListAll)) {
                    attendanceDedParamDAO.insertListAndSetId(attendanceDedParamDOListAll);
                }
            }

        }

        //保存方案适用设置
        ApplyToProgUpdateDTO applyToProgUpdateDTO = attendanceDedProgUpdateDTO.getApplyToProgUpdateDTO();
        applyToProgUpdateDTO.setBusProgType(ProgTypeEnum.ATTENDANCE_DED.getValue());
        applyToProgUpdateDTO.setBusProgId(attendanceDedProgDO.getId());
        applyToProgUpdateDTO.setMutex(true);
        Object obj = applyToProgService.update(applyToProgUpdateDTO, tokenUser);
        if (!(obj instanceof Integer)) {
            throw new JsolaException(JSON.toJSONString(obj));
        }
        HrLogKit.logForUpdate("修改员工考勤扣款方案", "updateApplyToProg", attendanceDedProgDO.getId(), tokenUser);
        //根据主键更新，只更新非null值
        return updateByIdSelective(attendanceDedProgDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... attendanceDedProgIds) {
        HrLogKit.logForDelete("批量删除员工考勤扣款方案", "deleteApplyToProgByIds"
                , Arrays.toString(attendanceDedProgIds), tokenUser);
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) attendanceDedProgIds);
    }


    @Override
    public AttendanceDedProgVO selectById(String attendanceDedProgId, String siteId) {
        AttendanceDedProgDO attendanceDedProgDO = selectDOById(attendanceDedProgId, siteId);
        if (attendanceDedProgDO == null) {
            return null;
        }
        return attendanceDedProgDO.to(AttendanceDedProgVO.class);
    }

    @Override
    public List<AttendanceDedProgListVO> select(AttendanceDedProgQuery attendanceDedProgQuery, String siteId) {
        List<AttendanceDedProgDO> attendanceDedProgDOList = selectDO(attendanceDedProgQuery, siteId);
        if (CollectionUtils.isEmpty(attendanceDedProgDOList)) {
            return attendanceDedProgDOList == null ? null : new ArrayList<>();
        }
        return attendanceDedProgDOList.stream()
                .map(attendanceDedProgDO -> attendanceDedProgDO.to(AttendanceDedProgListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(AttendanceDedProgQuery attendanceDedProgQuery, String siteId) {
        Example example = buildExample(attendanceDedProgQuery, siteId);
        return attendanceDedProgDAO.selectCountByExample(example);
    }

    @Override
    public Page<AttendanceDedProgListVO> selectPage(AttendanceDedProgQuery attendanceDedProgQuery, String siteId) {
        Example example = buildExample(attendanceDedProgQuery, siteId);
        Page<AttendanceDedProgDO> page = attendanceDedProgDAO.selectPageByExample(example,
                attendanceDedProgQuery.getPageNo(),
                attendanceDedProgQuery.getPageSize());

        return page.to(AttendanceDedProgListVO.class);
    }

    @Override
    public AttendanceDedProgDO selectDOById(String attendanceDedProgId, String siteId) {
        return listById(attendanceDedProgId, siteId);
    }

    @Override
    public List<AttendanceDedProgDO> selectDO(AttendanceDedProgQuery attendanceDedProgQuery, String siteId) {
        Example example = buildExample(attendanceDedProgQuery, siteId);
        return attendanceDedProgDAO.selectByExample(example);
    }


    /**
     * 根据查询参数，构建example
     *
     * @param attendanceDedProgQuery 查询参数
     * @param siteId                 所属站点id
     * @return example
     */
    private Example buildExample(AttendanceDedProgQuery attendanceDedProgQuery, String siteId) {
        Example example = new Example(AttendanceDedProgDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (attendanceDedProgQuery.getName() != null) {
            example.and().andLike("name", "%" + attendanceDedProgQuery.getName() + "%");
        }
        if (attendanceDedProgQuery.getRemark() != null) {
            example.and().andLike("remark", "%" + attendanceDedProgQuery.getRemark() + "%");
        }
        if (attendanceDedProgQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", attendanceDedProgQuery.getCompanyId());
        }
        if (attendanceDedProgQuery.getGmtCreateStart() != null &&
                attendanceDedProgQuery.getGmtCreateEnd() != null) {
            example.and().andBetween("gmtCreate", attendanceDedProgQuery.getGmtCreateStart(),
                    attendanceDedProgQuery.getGmtCreateEnd());
        }
        if (attendanceDedProgQuery.getCreateUserId() != null) {
            example.and().andLike("createUserId", "%" + attendanceDedProgQuery.getCreateUserId() + "%");
        }
        if (attendanceDedProgQuery.getGmtModifiedStart() != null &&
                attendanceDedProgQuery.getGmtModifiedEnd() != null) {
            example.and().andBetween("gmtModified", attendanceDedProgQuery.getGmtModifiedStart(),
                    attendanceDedProgQuery.getGmtModifiedEnd());
        }
        if (attendanceDedProgQuery.getModifiedUserId() != null) {
            example.and().andLike("modifiedUserId", "%" + attendanceDedProgQuery.getModifiedUserId() + "%");
        }
        // 排序
        ExampleKit.setExampleOrder(example, attendanceDedProgQuery.getOrders());
        return example;
    }

    @Override
    public List<AttendanceDedProgListVO> selectListAll(String companyId, String siteId) {
        AttendanceDedProgDO attendanceDedProgDOTmp = new AttendanceDedProgDO();
        attendanceDedProgDOTmp.setCompanyId(companyId);
        List<AttendanceDedProgDO> attendanceDedProgDOList = attendanceDedDAO.progListWithItem(attendanceDedProgDOTmp, siteId);
        if (CollectionUtils.isEmpty(attendanceDedProgDOList)) {
            return attendanceDedProgDOList == null ? null : new ArrayList<>();
        }
        List<ApplyToProgEmpeeInfoDTO> applyToProgEmpeeInfoDTOList = applyToProgService.getApplyToProgEmployee(ProgTypeEnum.ATTENDANCE_DED.getValue(), siteId, companyId);
        return attendanceDedProgDOList.stream()
                .map(attendanceDedProgDO -> {
                    AttendanceDedProgListVO attendanceDedProgListVO = attendanceDedProgDO.to(AttendanceDedProgListVO.class);
                    applyToProgEmpeeInfoDTOList.forEach(applyToProgEmpeeInfoDTO -> {
                        if (applyToProgEmpeeInfoDTO.getBusProgId().equals(attendanceDedProgDO.getId())) {
                            attendanceDedProgListVO.setMemberCount(applyToProgEmpeeInfoDTO.getEmpInfoDOList() == null ? 0 : applyToProgEmpeeInfoDTO.getEmpInfoDOList().size());
                        }
                    });

                    return attendanceDedProgListVO;
                })
                .collect(Collectors.toList());
    }

    @Override
    public AttendanceDedProgVO selectRelationById(String id, String siteId) {
        AttendanceDedProgUpdateDTO attendanceDedProgUpdateDTO = new AttendanceDedProgUpdateDTO();
        attendanceDedProgUpdateDTO.setId(id);
        AttendanceDedProgDO attendanceDedProgDO = attendanceDedDAO.selectRelationById(attendanceDedProgUpdateDTO, siteId);
        AttendanceDedProgVO attendanceDedProgVO = attendanceDedProgDO.to(AttendanceDedProgVO.class);
        attendanceDedProgVO.setApplyToProgVO(applyToProgService.selectByBusProgId(attendanceDedProgUpdateDTO.getId(), siteId));
        return attendanceDedProgVO;
    }
}




